package com.cash.channel.svc.logic;

import com.alibaba.fastjson.JSON;
import com.cash.channel.api.constant.Constant;
import com.cash.channel.api.exception.CashChannelException;
import com.cash.common.utils.MD5Util;
import com.cash.user.model.UserInfoModel;
import com.cash.user.service.CashCardBinService;
import com.cash.user.service.UserService;
import com.geex.support.kratos.contract.model.sign.ContractModel;
import com.geex.support.kratos.contract.model.sign.DocFactoryModel;
import com.geex.support.kratos.contract.model.sign.PersonalModel;
import com.geex.support.kratos.contract.service.ContractFactoryService;
import com.google.common.collect.Maps;
import geex.payment.model.pojo.RequestParameter;
import geex.payment.model.pojo.ResponseResult;
import geex.payment.service.QueryService;
import geex.payment.service.SigningService;
import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONObject;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateFormatUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.*;

@Slf4j
@Component
public class ProtocolLogic {

    @Autowired(required = false)
    private SigningService signingService;

    @Autowired(required = false)
    private QueryService queryService;
    @Autowired(required = false)
    private CashCardBinService cashCardBinService;
    @Autowired(required = false)
    private UserService userService;
    @Autowired(required = false)
    private ContractFactoryService contractFactoryService;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Resource
    private RedisTemplate redisTemplate;
    /**
     * 协议签约
     *
     * @param compayTag  主体
     * @param instCode   银行卡code
     * @param cardNo     卡号
     * @param userName   用户名
     * @param userMobile 预留手机号
     * @param userIdNo   身份证
     * @return
     */
    public Map<String, Object> signProtocol(String compayTag, String instCode, String cardNo, String userName, String userMobile, String userIdNo) throws Exception {
        Map<String, Object> resultMap = Maps.newHashMap();
        Map<String, String> map = new HashMap<>();
        map.put("companyTag", compayTag);
        map.put("instCode", instCode);
        map.put("cardNo", cardNo);
        map.put("userName", userName);
        map.put("userMobile", userMobile);
        map.put("userIdNo", userIdNo);
        log.info("signProtocol begin:" + map);
        try {
            log.info("signProtocol..requestMap" + map);
            ResponseResult res = signingService.signing(geRequestParameter(map));
            log.info("signProtocol Res:" + res);
            if (!"000000".equals(res.getResponseCode())) {
                throw new Exception(res.getResponseMsg());
            }
            JSONObject jsonObject = JSONObject.fromObject(res.getData());
            resultMap.put("uniqueCode", jsonObject.getString("uniqueCode"));
            return resultMap;
        } catch (Exception e) {
            log.error("signProtocol ERROR:" + e.getMessage(), e);
            throw new Exception("协议签约check失败!" + e.getMessage());
        }

    }

    /**
     * 协议签约查询
     *
     * @param compayTag
     * @param cardNo
     * @return
     * @throws Exception
     */
    public Map<String, Object> signingQuery(String compayTag, String cardNo, String userMobile,String uid,String bankName)throws Exception  {
        log.info("SigningQuery compayTag " + compayTag + "cardNo" + cardNo+"userMobile"+userMobile);
        Map<String, Object> map = Maps.newHashMap();
        String bankCode="";
        try {
            ResponseResult res = queryService.needSigningQuery(compayTag, cardNo);
            log.info("needSigningQuery Res:" + res);
            if (!"000000".equals(res.getResponseCode())) {
                throw new Exception(res.getResponseMsg());
            }
            //签约状态查询
            JSONObject jsonObject = JSONObject.fromObject(res.getData());
            String alreadySign = jsonObject.getString("alreadySign");
            if ("Y".equals(alreadySign)) {
                map.put("needMakeProtocol", false);
                map.put("uniqueCode", "");
                return map;
            } else if ("N".equals(alreadySign)) {
                //发起协议签约
                bankCode=checkCard(cashCardBinService.getBankCodeByCardNo(cardNo),bankName);
             UserInfoModel userInfoModel = userService.findUserInfoByUid(uid);
                if (userInfoModel == null || StringUtils.isEmpty(userInfoModel.getcIdno())) {
                    throw  new Exception("未找到用户信息!");
                }
                Map<String, Object> signMap = signProtocol("JKJR", bankCode, cardNo, userInfoModel.getcName(), userMobile, userInfoModel.getcIdno());
                map.put("needMakeProtocol", true);
                map.put("uniqueCode", MapUtils.getString(signMap, "uniqueCode"));
                return map;
            }else {
                throw new  Exception("未知签约状态!");
            }
        } catch (Exception e) {
            log.error("signConfirm ERROR:" + e.getMessage(), e);
            throw new Exception("查询签约状态失败!" + e.getMessage());
        }
    }

    public RequestParameter geRequestParameter(Map<String, String> map) {
        RequestParameter requestParameter = new RequestParameter();
        requestParameter.setData(map);
        requestParameter.setRequestTime(new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()));
        return requestParameter;
    }

    public RequestParameter submitProtocol(String uniqueCode, String smsCode, String uid, String cardNo, String userMobile) throws Exception {
        Map<String, String> map = new HashMap<>();
        UserInfoModel userInfoModel = userService.findUserInfoByUid(uid);
        if (userInfoModel == null || StringUtils.isEmpty(userInfoModel.getcIdno())) {
            throw  new Exception("未找到用户信息!");
        }
        map.put("uniqueCode", uniqueCode);
        map.put("smsCode", smsCode);
        map.put("cardNo", cardNo);
        map.put("userName", userInfoModel.getcName());
        map.put("userMobile", userMobile);
        map.put("userIdNo", userInfoModel.getcIdno());
        return  geRequestParameter(map);
    }

    public String  checkCard(Map<String,Object> map,String bankName)throws Exception{
        log.info("卡bin信息"+map);
        if(null==map){
            throw new Exception("查询卡bin信息失败!");
            }else{
            if(!MapUtils.getString(map,"bankName").contains(bankName)){
                throw new Exception("卡bin校验失败!");
            }else {
                return MapUtils.getString(map,"bankCode");
            }
        }
    }

    /**
     *  生成授权委托合同书
     * @param appId
     * @param cardNo
     * @param userMobile
     * @param bankName
     * @param uid
     * @throws Exception
     */
    public void generateDoc(String appId,String cardNo,String userMobile,String bankName,String uid)throws Exception {
        DocFactoryModel docFactoryModel=new DocFactoryModel();
        try {
            UserInfoModel userInfoModel = userService.findUserInfoByUid(uid);
            if (userInfoModel == null || StringUtils.isEmpty(userInfoModel.getcIdno())) {
                throw  new Exception("未找到用户信息!");
            }
            docFactoryModel.setAppId(appId);
            docFactoryModel.setContractType(10903);
            docFactoryModel.setDocVersion(1);
            docFactoryModel.setSelfsign(0);
            List<PersonalModel> personalModels=new ArrayList<>();
            PersonalModel personalModel=new PersonalModel();
            personalModel.setSignImageType(1);
            personalModel.setOpenflag(1);
            personalModel.setMobile(userMobile);
            personalModel.setName(userInfoModel.getcName());
            personalModel.setEmail(userInfoModel.getcEmail());
            personalModel.setIdentity(userInfoModel.getcIdno());
            personalModels.add(personalModel);
            docFactoryModel.setPersonalModels(personalModels);
            Map<String,String> map=Maps.newHashMap();
            map.put("name",userInfoModel.getcName());
            map.put("mobile",userMobile);
            map.put("idNo",userInfoModel.getcIdno());
            map.put("account",cardNo);
            map.put("bank",bankName);
            map.put("signDate",DateFormatUtils.format(new Date(), "yyyy年MM月dd日"));
            docFactoryModel.setObject(map);
            log.info("生成合同客户委托扣款授权书 begin...param"+docFactoryModel);
            ContractModel contractModel = contractFactoryService.docCompletionSignByType(docFactoryModel);
            log.info("生成合同客户委托扣款授权书 end...result"+contractModel);
        }catch (Exception e){
            log.error("生成合同客户委托扣款授权书失败!");
            throw e;
        }
    }

    public Map<String, Object> signingQueryChannel(String name, String idNo, String compayTag, String cardNo, String userMobile, String bankCode, String channelStr) throws CashChannelException {
        log.info("SigningQueryChannel compayTag " + compayTag + "cardNo" + cardNo + "userMobile" + userMobile);
        Map<String, Object> map = Maps.newHashMap();
        try {
            ResponseResult res = queryService.needSigningQuery(compayTag, cardNo);
            log.info("needSigningQuery Res:" + res);
            if (!"000000".equals(res.getResponseCode())) {
                throw new CashChannelException(res.getResponseMsg());
            }
            //签约状态查询
            JSONObject jsonObject = JSONObject.fromObject(res.getData());
            String alreadySign = jsonObject.getString("alreadySign");
            if ("Y".equals(alreadySign)) {
                map.put("needMakeProtocol", false);
                map.put("uniqueCode", "");
                return map;
            } else if ("N".equals(alreadySign)) {
                //发起协议签约
                Map<String, Object> signMap = signProtocol("JKJR", bankCode, cardNo, name, userMobile, idNo);
                map.put("needMakeProtocol", true);
                map.put("uniqueCode", MapUtils.getString(signMap, "uniqueCode"));
                String smsCacheKey = MD5Util.md5(name + idNo, channelStr);
                this.redisTemplate.opsForValue().set(smsCacheKey, MapUtils.getString(signMap, "uniqueCode"));
                return map;
            } else {
                throw new CashChannelException("未知签约状态!");
            }
        } catch (Exception e) {
            log.error("signConfirm ERROR:" + e.getMessage(), e);
            throw new CashChannelException("查询签约状态失败!" + e.getMessage());
        }
    }

    public ResponseResult submitProtocolChannel(String name, String idNo, String cardNo, String userMobile, String smsCode, String channelStr) throws Exception {
        Map<String, String> map = new HashMap<>();
        String smsCacheKey = MD5Util.md5(name + idNo, channelStr);
        Object object = this.redisTemplate.opsForValue().get(smsCacheKey);
        if (object == null) {
            throw new Exception("请先获取验证码");
        }
        String uniqueCode = this.redisTemplate.opsForValue().get(smsCacheKey).toString();
        map.put("uniqueCode", uniqueCode);
        map.put("smsCode", smsCode);
        map.put("cardNo", cardNo);
        map.put("userName", name);
        map.put("userMobile", userMobile);
        map.put("userIdNo", idNo);
        RequestParameter requestParameter = geRequestParameter(map);

        log.info("submitProtocolChannel...... requestParameter" + requestParameter);
        ResponseResult res = signingService.signConfirmTwo(requestParameter);
        log.info("submitProtocolChannel result" + res);
        if (res == null || !"000000".equals(res.getResponseCode())) {
            throw new Exception(res.getResponseMsg());
        }
        return res;
    }

    public void sendSubmitProtocol(com.alibaba.fastjson.JSONObject mqParams) {
        try {
            rabbitTemplate.convertAndSend("geex" , Constant.ProConstant.PROTOCOL_SUBMIT_QUEUE, mqParams.toJSONString());
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw e;
        }
    }
}
